<!DOCTYPE HTML>
<html lang="en">
<head>
  <meta charset="utf8">
  <title>Test for Web Console commands registration.</title>
  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript;version=1.8" src="common.js"></script>
  <!-- Any copyright is dedicated to the Public Domain.
     - http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>Test for Web Console commands registration.</p>
<p id="quack"></p>

<script class="testbody" type="text/javascript;version=1.8">
SimpleTest.waitForExplicitFinish();

let gState;
let tests;

let {WebConsoleCommands} = require("devtools/server/actors/utils/webconsole-utils");

function evaluateJS(input) {
  return new Promise((resolve) => gState.client.evaluateJS(input, resolve));
}

function* evaluateJSAndCheckResult(input, result) {
  let response = yield evaluateJS(input);
  checkObject(response, {result});
}

function startTest()
{
  removeEventListener("load", startTest);

  attachConsoleToTab(["PageError"], onAttach);
}

function onAttach(aState, aResponse)
{
  gState = aState;

  runTests(tests, testEnd);
}

tests = [
  Task.async(function* registerNewCommand() {
    let win;
    WebConsoleCommands.register("setFoo", (owner, value) => {
      owner.window.foo = value;
      return "ok";
    });

    ok(WebConsoleCommands.hasCommand("setFoo"),
        "The command should be registered");

    let command = "setFoo('bar')";
    let response = yield evaluateJS(command);

    checkObject(response, {
      from: gState.actor,
      input: command,
      result: "ok"
    });
    is(top.foo, "bar", "top.foo should equal to 'bar'");
    nextTest();
  }),

  Task.async(function* wrapCommand() {
    let origKeys = WebConsoleCommands.getCommand("keys");

    let newKeys = (...args) => {
      let [owner, arg0] = args;
      if (arg0 === ">o_/") {
        return "bang!";
      }
      else {
        return origKeys(...args);
      }
    };

    WebConsoleCommands.register("keys", newKeys);
    is(WebConsoleCommands.getCommand("keys"), newKeys,
        "the keys() command should have been replaced");

    let response = yield evaluateJS("keys('>o_/')");
    checkObject(response, {
      from: gState.actor,
      result: "bang!"
    });

    response = yield evaluateJS("keys({foo: 'bar'})");
    checkObject(response, {
      from: gState.actor,
      result: {
        class: "Array",
        preview: {
          items: ["foo"]
        }
      }
    });

    WebConsoleCommands.register("keys", origKeys);
    is(WebConsoleCommands.getCommand("keys"), origKeys,
      "the keys() command should be restored");
    nextTest();
  }),

  Task.async(function* unregisterCommand() {
    WebConsoleCommands.unregister("setFoo");

    let response = yield evaluateJS("setFoo");

    checkObject(response, {
      from: gState.actor,
      input: "setFoo",
      result: {
        type: "undefined"
      },
      exceptionMessage: /setFoo is not defined/
    });
    nextTest();
  }),

  Task.async(function* registerAccessor() {
    WebConsoleCommands.register("$foo", {
      get(owner) {
        let foo = owner.window.frames[0].window.document.getElementById("quack");
        return owner.makeDebuggeeValue(foo);
      }
    });
    let command = "$foo.textContent = '>o_/'";
    let response = yield evaluateJS(command);

    checkObject(response, {
      from: gState.actor,
      input: command,
      result: ">o_/"
    });
    is(document.getElementById("quack").textContent, ">o_/",
        "#foo textContent should equal to \">o_/\"");
    WebConsoleCommands.unregister("$foo");
    ok(!WebConsoleCommands.hasCommand("$foo"), "$foo should be unregistered");
    nextTest();
  }),

  Task.async(function* unregisterAfterOverridingTwice() {
    WebConsoleCommands.register("keys", (owner, obj) => "command 1");
    info("checking the value of the first override");
    yield evaluateJSAndCheckResult("keys('foo');", "command 1");

    let orig = WebConsoleCommands.getCommand("keys");
    WebConsoleCommands.register("keys", (owner, obj) => {
      if (obj === "quack")
        return "bang!";
      return orig(owner, obj);
    });

    info("checking the values after the second override");
    yield evaluateJSAndCheckResult("keys({});", "command 1");
    yield evaluateJSAndCheckResult("keys('quack');", "bang!");

    WebConsoleCommands.unregister("keys");

    info("checking the value after unregistration (should restore " +
      "the original command)");
    yield evaluateJSAndCheckResult("keys({});", {
      class: "Array",
      preview: {items: []}
    });
    nextTest();

  })
];

function testEnd()
{
  // If this is the first run, reload the page and do it again.
  // Otherwise, end the test.
  delete top.foo;
  closeDebugger(gState, function() {
    gState = null;
    SimpleTest.finish();
  });
}

addEventListener("load", startTest);
</script>
</body>
</html>

